
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

LIBRARY LPM;
USE LPM.LPM_COMPONENTS.ALL;

USE WORK.TYPES.ALL;

ENTITY Ifetch IS
    PORT (
        SIGNAL Instruct         : OUT    INSTRUCTION;
        SIGNAL PC_plus_4_out    : OUT    MEMADDR;
        SIGNAL Add_result       : IN     MEMADDR;
        SIGNAL Branch           : IN     STD_LOGIC;
        SIGNAL Zero             : IN     STD_LOGIC;
        SIGNAL PC_out           : OUT    MEMADDR;
        SIGNAL clock, reset     : IN     STD_LOGIC);
END Ifetch;

ARCHITECTURE behavior OF Ifetch IS
    -- Incluido para FPGA com memória sincrona
    component rom
        PORT (
            address : IN    MEMADDR;
            clock   : IN    STD_LOGIC  := '1';
            q       : OUT   INSTRUCTION
        );
    end component;

    SIGNAL PC, PC_plus_4         : MEMADDR := (OTHERS => '0');
    SIGNAL next_PC, next_PC_0    : MEMADDR := (OTHERS => '0');
BEGIN

    rom_inst: rom
    PORT MAP (
        address => PC,
        q       => Instruct,
        clock   => clock
    );

    -- Copia os sinais de saida permitindo a leitura de dentro do modulo
    PC_out        <= PC;
    PC_plus_4_out <= PC_plus_4;

    -- Incrementa o pc em 4        
    PC_plus_4 <= PC + 4;

    -- Mux para selecionar o Branch ou PC + 4        
    next_PC <= Add_result   WHEN ( ( Branch = '1' ) AND ( Zero = '1' ) ) 
                            ELSE PC_plus_4;

    -- Guarda PC no registrador e carrega o proximo PC na borda de clock
    PROCESS
        BEGIN
            WAIT UNTIL ( clock'EVENT ) AND ( clock = '1' );
            IF reset = '1' THEN
                   PC <= (OTHERS => '0'); 
            ELSE 
                   PC <= next_PC;
            END IF;
    END PROCESS;
END behavior;


